# -*- coding:utf-8 -*-
# @author mark
# @since 2022/03/19 10:03:49
# @modified 2022/03/20 21:30:05
# @filename driver_leveldbpy.py

import leveldbpy

class LevelDBProxy:

    def __init__(self, path = None, snapshot = None, 
            max_open_files = 1000,
            block_cache_size = 8 * (2<<20), 
            write_buffer_size = 2 * (2<<20)):
        """通过leveldbpy来实现leveldb的接口代理，因为leveldb没有提供Windows环境的支持"""

        if snapshot != None:
            self._db = snapshot
        else:
            assert path != None
            self._db = leveldbpy.DB(path.encode("utf-8"), 
                create_if_missing = True, 
                block_cache_size = block_cache_size,
                max_open_files = max_open_files,
                write_buffer_size = write_buffer_size)

    def Get(self, key):
        return self._db.get(key)

    def Put(self, key, value, sync = False):
        return self._db.put(key, value, sync = sync)

    def Delete(self, key, sync = False):
        return self._db.delete(key, sync = sync)

    def RangeIter_reverse(self, iterator, key_from = None, key_to = None):
        if key_to:
            iterator.seek(key_to)     # cur >= key_to
            if not iterator.valid():  # 如果没有匹配的，移动到尾部
                iterator.seekLast()
        else:
            iterator.seekLast()

        def try_seek_prev():
            try:
                return iterator.prev()
            except StopIteration:
                return None

        # 反向遍历有三种情况:
        # 1. 没有命中key并且后面也没有任何值，需要往前移动
        # 2. 找到key后面的一个值，需要往前移动
        # 3. 刚好命中key，不需要处理

        if not iterator.valid():
            # 一个匹配的都没有，直接返回
            return

        if key_to != None and iterator.key() > key_to:
            # cur > key_to: 需要 seek prev
            try_seek_prev()

        while True:
            try:
                if not iterator.valid():
                    return

                if key_from != None and iterator.key() < key_from:
                    return

                if iterator._keys_only:
                    yield iterator.key()
                else:
                    yield (iterator.key(), iterator.value())

                iterator.prev()
            except StopIteration:
                return

    def RangeIter(self, 
            key_from = None, 
            key_to = None, 
            reverse = False, 
            include_value = True, 
            fill_cache = False):
        """返回区间迭代器
        @param {str}  key_from       开始的key（包含）
        @param {str}  key_to         结束的key（包含）
        @param {bool} reverse        是否反向查询
        @param {bool} include_value  是否包含值
        """
        if include_value:
            keys_only = False
        else:
            keys_only = True

        iterator = self._db.iterator(keys_only = keys_only)

        if reverse:
            for item in self.RangeIter_reverse(iterator, key_from, key_to):
                yield item
            return

        if key_from:
            iterator.seek(key_from)
        else:
            iterator.seekFirst()

        while True:
            if not iterator.valid():
                # raise StopIteration()
                return
            key = iterator.key()
            # print(key, key_to)
            if key_to and key > key_to:
                # raise StopIteration()
                return
            
            if include_value:
                yield iterator.key(), iterator.value()
            else:
                yield iterator.key()

            try:
                iterator.next()
            except StopIteration:
                return

    def CreateSnapshot(self):
        return LevelDBProxy(snapshot = self._db.snapshot())

    def Write(self, batch_proxy, sync = False):
        """执行批量操作"""
        batch = leveldbpy.WriteBatch()
        for key in batch_proxy._puts:
            value = batch_proxy._puts[key]
            batch.put(key, value)
        for key in batch_proxy._deletes:
            batch.delete(key)
        return self._db.write(batch, sync)

